<<<<<<< HEAD Lab 3: Visualizing 2D patterns in oceanographic cruise data

This lab focuses on visualizing temporal and spatial patterns in oceanographic cruise data i.e. how do parameters vary upriver compared with the open ocean or how do parameters vary with depth or how does one station change over the season? The tools you are introduced to here can be used to graph and analyze data in your labs, your independent research projects and the cruise data gathered throughout the semester. Be sure to save any scripts that you develop so you can continue to use them.

A. Visualization of discrete data using contour plots

In this section, we are going to visualize how parameters vary at each station for each cruise.

A1. Importing data

We are going to look at some of the discrete data, taken from the Niskin bottles. To do this, we need to create another csv file from the Colby_cruise_data_2012-2017.xlsx sheet like last week. But let’s start by setting our working directory.

setwd('C:/Users/Catherine/Documents/REUColbyCoding/CMdev/RbigelowCMdev/Lab03_2018')

Creating discrete data csv file

  1. Open Colby_cruise_data_2012-2017.xlsx
  2. Open a new blank Excel file
  3. Go to the “discrete data” tab
  4. Select and copy the following columns: date, cruise, station, depth, SiO4, NO3+2, PO4, NH4, Bacteria Conc, Viral Conc, Chl Total, CHL <20um, CHL<3um, Flowcam Biomass.
  5. Paste the columns into the blank Excel file
  6. Delete the rows from 2012 - 2015 and 2017 i.e. so the only year left is 2016.
  7. Delete the dates column and the top two rows (the row of units and the row contain the units of a few of the columns)
  8. Press CTRL-F on Windows, or the Command-F on a Mac, to bring up the “Find and Replace” window.
  9. Go to the Replace tab, enter “Cruise” in the “Find What” box and nothing in the “Replace with” box, hit “Replace all”
  10. Repeat 9 for the word “BLOS” and close the window
  11. Save the file as a CSV (Comma Delimited) with a sensible name e.g. Colby_discrete_data_2016.csv

Importing the data

Let’s import the data as before.

# read in the whole csv file
discreteDATA <- read.csv('Colby_discrete_data_2016.csv', header = TRUE)

A2. Data wrangling and creating contour plots

We are going to create a contour plot for the surface data, for station vs cruise. To do this we are going to use the plotly library, so let’s import the package, and load it into our workspace

install.packages("plotly")

library("plotly")

Now we can extract the surface data from our DATA data frame and plot the result.

#extracting data with a depth of less than 5m
surface = discreteDATA[discreteDATA$Depth < 5,]
#plotting the contour plot
p = plot_ly(x= surface$ID, y = surface$Station, z = surface$NO3.2, 
        type = "contour")
#adding the axis labels and title
layout(p, xaxis = list(title = 'Cruise number'), yaxis = list(title = 'Station number'), title = "NO3.2 (uM)")

B. Visualization of continuous data using section plots

In this section, we are going to visualize spatial changes in terms of depth and station for a given cruise.

B1. Importing and wrangling data

For this section, we are going to use the csv file we made last day which contains all the continuous CTD profiles, and extract out one cruise.

#importing the CTD data
CTDdata <- read.csv('Colby_cruise_data_2012-2017.csv')
#making a list of the dates of each cruise
dates <- unique(CTDdata[['Date']])
#extracting data for the cruise on September 8th 2016
cruiseData <- CTDdata[CTDdata[['Date']] == dates[17],]

We could use the same plotting function as before to plot e.g. Temperature:

# plotting the contour plot
p <- plot_ly(x = cruiseData$Station, y = cruiseData$Depth, z = cruiseData$Temperature, type = "contour", contours = list(showlines = FALSE))
#adding the labels and reversing the y-axis
layout(p,yaxis = list(autorange = "reversed",title = 'Depth (m)'),
       xaxis = list(title = 'Station number'), 
       title = "Temperature (deg C)")

We end up with distinct bands at the deeper depths. This is because of the interpolation that has been done by the plotting function. Stations 1 - 3 are 50m or shallower, hence the only data at the deep depths are from station 4. The plotting function then assumes that is the value at that depth for all stations, which is incorrect. Let’s try a different method instead.

B2. Coding technique: for-loops

When you want to repeat the same bit of code a certain number of times, a for-loop can be your friend. For example, if you would like to plot a section for each cruise, rather than type out the code for each cruise individually, we can just write it once and iterate or loop over the code.

Let’s start with a simple example:

Example: print the statement “hello” four times

for (ii in 1:4) {
  print("hello")
}
[1] "hello"
[1] "hello"
[1] "hello"
[1] "hello"

Example: print the statement “hello” four times, including the number at the start of the statement e.g. “1 hello”

for (ii in 1:4) {
  print(paste(ii,"hello"))
}
[1] "1 hello"
[1] "2 hello"
[1] "3 hello"
[1] "4 hello"

B3. Plotting oceanographic section

For this method, we’ll make use of the fields package, which provides tools for analyzing and visualizing spatial data.

library("fields")

To do this plot, we are goint to need to manipulate our data a bit more. We need to make our Temperature data into a matrix, where each row represents a depth, and each column represents a different station. The depth data are not consistent; they are all at irregular intervals. Therefore, to put the temperature data into a matrix, we are going to need to bin the data into regular depth intervals of 1m.

stationLat <- c(43+54.130/60, 43+51.8/60, 43+48.56/60, 43+44.87/60)
#creating an empty matrix with 100 rows (i.e. for 100 depths) and 4 columns (i.e. one for each station)
TEM <- matrix(NA,nrow = 100, ncol = 4)
#looping through each station
for (st in 1:4){
  #looping through each depth interval (from 1m to 100m)
  for (j in 1:100){
    #extracting the relevant station from the cruiseData data frame
    stationData <- cruiseData[cruiseData$Station == st,]
    
    #binned temperature value for given depth interval
    temp = mean(stationData[ceiling(stationData$Depth)==j,'Temperature']) 
    
    #assinging the binned temperature to the j-th row and st-th column of the TEM matrix
    TEM[j,st] <- temp
  }
}

Now we’ve created our matrix, we can plot the temperature section.

image.plot(x=stationLat[4:1],y=-100:-1,t(TEM[100:1,4:1]),
           zlim=c(8,20),
           col=tim.colors(24),
           xlab='Latitude (deg N)',
           ylab='Depth (m)',
           main='Cruise 20160908',
           legend.lab='Temperature (C)',
legend.line=2.5)

Example: How do we change the color scheme?

  1. We can use one of the R color palettes e.g. heat.colors, terrain.colors, topo.colors as the col argument in place of the tim.colors argument.
  2. We can use one of the Color Brewer palettes. Color Brewer was a project which created a lot of different color palettes for thematic maps. There are different types of color palettes depending on your needs (e.g. sequential color scale, diverging color scale, quantative scales). It has a cool web-interface (http://colorbrewer2.org/#) where you can play around with the palettes. What is good about Color Brewer is the sequential color palettes (the type we used in our above section plot) are made from at most 3 colors, and are altered by changing the hue. This makes the maps colorblind-friendly and prevents artificial sharp edges between color changes. R has a package for the Color Brewer palettes. Check out the help to see a list of the sequential palette names you can use.
library("RColorBrewer")
colpal <- colorRampPalette(brewer.pal(9,'YlOrRd'))   # make colors
image.plot(x=stationLat[4:1],y=-100:-1,t(TEM[100:1,4:1]),
           zlim=c(8,20),
           col=colpal(60),
           xlab='Station',
           ylab='Depth (m)',
           main='Cruise 20160908',
           legend.lab='Temperature (C)',
legend.line=2.5)

B4. Coding technique: Functions

Functions are blocks of code which when called, perform a specific task. Usually you give them an input and they give you an output. We’ve used lots of different R in-built functions e.g. read.csv, image.plot, etc. We can write our own functions for our own specific tasks.

Example: write a function which adds two numbers

addition <- function(a,b){
  return(a+b)
}
addition(9,3)
[1] 12

Let’s write a function which turns a variable from the CTDdata into a matrix (for plotting as a segment). To do this, we’ll just copy the code from above and wrap it in a function.

col2matrix <- function(columnName){
  
  #creating an empty matrix with 100 rows (i.e. for 100 depths) and 4 columns (i.e. one for each station)
  TEM <- matrix(NA,nrow = 100, ncol = 4)
  
  #looping through each station
  for (st in 1:4){
    #looping through each depth interval (from 1m to 100m)
    for (j in 1:100){
      #extracting the relevant station from the cruiseData data frame
      stationData <- cruiseData[cruiseData$Station == st,]
      
      #binned temperature value for given depth interval
      temp = mean(stationData[ceiling(stationData$Depth)==j,columnName]) 
      
      #assinging the binned temperature to the j-th row and st-th column of the TEM matrix
      TEM[j,st] <- temp
    }
  }
  return(TEM)
}

Assignment (in lab)

    1. Plot a contour plot for different discrete variables (use the col2matrix function we just wrote to wrangle your data into the correct format). Can you figure out how to change the color scheme?
    2. Try plotting a station-by-depth contour plot for 1 cruise (instead of station-by-cruise)
    3. Try plotting a depth-by-cruise contour plot for 1 station.
    4. Try plotting a contour plot of your choice for a different cruise.
  1. Plot an oceanographic section for different variables from the CTD casts. Remember to change the limits of the color scale by adjusting the zlim argument to image.plot.
LS0tDQp0aXRsZTogIkxhYiAzOiBWaXN1YWxpemluZyAyRCBwYXR0ZXJucyBpbiBvY2Vhbm9ncmFwaGljIGNydWlzZSBkYXRhIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KVGhpcyBsYWIgZm9jdXNlcyBvbiB2aXN1YWxpemluZyB0ZW1wb3JhbCBhbmQgc3BhdGlhbCBwYXR0ZXJucyBpbiBvY2Vhbm9ncmFwaGljIGNydWlzZSBkYXRhIGkuZS4gaG93IGRvIHBhcmFtZXRlcnMgdmFyeSB1cHJpdmVyIGNvbXBhcmVkIHdpdGggdGhlIG9wZW4gb2NlYW4gb3IgaG93IGRvIHBhcmFtZXRlcnMgdmFyeSB3aXRoIGRlcHRoIG9yIGhvdyBkb2VzIG9uZSBzdGF0aW9uIGNoYW5nZSBvdmVyIHRoZSBzZWFzb24/IFRoZSB0b29scyB5b3UgYXJlIGludHJvZHVjZWQgdG8gaGVyZSBjYW4gYmUgdXNlZCB0byBncmFwaCBhbmQgYW5hbHl6ZSBkYXRhIGluIHlvdXIgbGFicywgeW91ciBpbmRlcGVuZGVudCByZXNlYXJjaCBwcm9qZWN0cyBhbmQgdGhlIGNydWlzZSBkYXRhIGdhdGhlcmVkIHRocm91Z2hvdXQgdGhlIHNlbWVzdGVyLiBCZSBzdXJlIHRvIHNhdmUgYW55IHNjcmlwdHMgdGhhdCB5b3UgZGV2ZWxvcCBzbyB5b3UgY2FuIGNvbnRpbnVlIHRvIHVzZSB0aGVtLg0KDQojIEEuIFZpc3VhbGl6YXRpb24gb2YgZGlzY3JldGUgZGF0YSB1c2luZyBjb250b3VyIHBsb3RzDQoNCkluIHRoaXMgc2VjdGlvbiwgd2UgYXJlIGdvaW5nIHRvIHZpc3VhbGl6ZSBob3cgcGFyYW1ldGVycyB2YXJ5IGF0IGVhY2ggc3RhdGlvbiBmb3IgZWFjaCBjcnVpc2UuDQoNCiMjIEExLiBJbXBvcnRpbmcgZGF0YQ0KDQpXZSBhcmUgZ29pbmcgdG8gbG9vayBhdCBzb21lIG9mIHRoZSBkaXNjcmV0ZSBkYXRhLCB0YWtlbiBmcm9tIHRoZSBOaXNraW4gYm90dGxlcy4gVG8gZG8gdGhpcywgd2UgbmVlZCB0byBjcmVhdGUgYW5vdGhlciBjc3YgZmlsZSBmcm9tIHRoZSBDb2xieV9jcnVpc2VfZGF0YV8yMDEyLTIwMTcueGxzeCBzaGVldCBsaWtlIGxhc3Qgd2Vlay4gQnV0IGxldCdzIHN0YXJ0IGJ5IHNldHRpbmcgb3VyIHdvcmtpbmcgZGlyZWN0b3J5Lg0KDQpgYGB7cn0NCnNldHdkKCdDOi9Vc2Vycy9DYXRoZXJpbmUvRG9jdW1lbnRzL1JFVUNvbGJ5Q29kaW5nL0NNZGV2L1JiaWdlbG93Q01kZXYvTGFiMDNfMjAxOCcpDQpgYGANCg0KIyMjIENyZWF0aW5nIGRpc2NyZXRlIGRhdGEgY3N2IGZpbGUNCg0KMS4gT3BlbiBDb2xieV9jcnVpc2VfZGF0YV8yMDEyLTIwMTcueGxzeA0KMi4gT3BlbiBhIG5ldyBibGFuayBFeGNlbCBmaWxlDQoyLiBHbyB0byB0aGUgImRpc2NyZXRlIGRhdGEiIHRhYg0KMy4gU2VsZWN0IGFuZCBjb3B5IHRoZSBmb2xsb3dpbmcgY29sdW1uczogZGF0ZSwgY3J1aXNlLCBzdGF0aW9uLCBkZXB0aCwgU2lPNCwJTk8zKzIsCVBPNCwJTkg0LAlCYWN0ZXJpYSBDb25jLAlWaXJhbCBDb25jLAlDaGwgVG90YWwsCUNITCA8MjB1bSwJQ0hMPDN1bSwJRmxvd2NhbSBCaW9tYXNzLg0KNS4gUGFzdGUgdGhlIGNvbHVtbnMgaW50byB0aGUgYmxhbmsgRXhjZWwgZmlsZQ0KNi4gRGVsZXRlIHRoZSByb3dzIGZyb20gMjAxMiAtIDIwMTUgYW5kIDIwMTcgaS5lLiBzbyB0aGUgb25seSB5ZWFyIGxlZnQgaXMgMjAxNi4NCjcuIERlbGV0ZSB0aGUgZGF0ZXMgY29sdW1uIGFuZCB0aGUgdG9wIHR3byByb3dzICh0aGUgcm93IG9mIHVuaXRzIGFuZCB0aGUgcm93IGNvbnRhaW4gdGhlIHVuaXRzIG9mIGEgZmV3IG9mIHRoZSBjb2x1bW5zKQ0KOC4gUHJlc3MgQ1RSTC1GIG9uIFdpbmRvd3MsIG9yIHRoZSBDb21tYW5kLUYgb24gYSBNYWMsIHRvIGJyaW5nIHVwIHRoZSAiRmluZCBhbmQgUmVwbGFjZSIgd2luZG93Lg0KOS4gR28gdG8gdGhlIFJlcGxhY2UgdGFiLCBlbnRlciAiQ3J1aXNlIiBpbiB0aGUgIkZpbmQgV2hhdCIgYm94IGFuZCBub3RoaW5nIGluIHRoZSAiUmVwbGFjZSB3aXRoIiBib3gsIGhpdCAiUmVwbGFjZSBhbGwiDQoxMC4gUmVwZWF0IDkgZm9yIHRoZSB3b3JkICJCTE9TIiBhbmQgY2xvc2UgdGhlIHdpbmRvdw0KMTEuIFNhdmUgdGhlIGZpbGUgYXMgYSBDU1YgKENvbW1hIERlbGltaXRlZCkgd2l0aCBhIHNlbnNpYmxlIG5hbWUgZS5nLiBDb2xieV9kaXNjcmV0ZV9kYXRhXzIwMTYuY3N2DQoNCiMjIyBJbXBvcnRpbmcgdGhlIGRhdGENCg0KTGV0J3MgaW1wb3J0IHRoZSBkYXRhIGFzIGJlZm9yZS4NCg0KYGBge3J9DQojIHJlYWQgaW4gdGhlIHdob2xlIGNzdiBmaWxlDQpkaXNjcmV0ZURBVEEgPC0gcmVhZC5jc3YoJ0NvbGJ5X2Rpc2NyZXRlX2RhdGFfMjAxNi5jc3YnLCBoZWFkZXIgPSBUUlVFKQ0KYGBgDQoNCiMjIEEyLiBEYXRhIHdyYW5nbGluZyBhbmQgY3JlYXRpbmcgY29udG91ciBwbG90cw0KDQpXZSBhcmUgZ29pbmcgdG8gY3JlYXRlIGEgY29udG91ciBwbG90IGZvciB0aGUgc3VyZmFjZSBkYXRhLCBmb3Igc3RhdGlvbiB2cyBjcnVpc2UuIFRvIGRvIHRoaXMgd2UgYXJlIGdvaW5nIHRvIHVzZSB0aGUgYHBsb3RseWAgbGlicmFyeSwgc28gbGV0J3MgaW1wb3J0IHRoZSBwYWNrYWdlLCBhbmQgbG9hZCBpdCBpbnRvIG91ciB3b3Jrc3BhY2UNCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KDQpsaWJyYXJ5KCJwbG90bHkiKQ0KYGBgDQoNCk5vdyB3ZSBjYW4gZXh0cmFjdCB0aGUgc3VyZmFjZSBkYXRhIGZyb20gb3VyIGBEQVRBYCBkYXRhIGZyYW1lIGFuZCBwbG90IHRoZSByZXN1bHQuDQoNCmBgYHtyfQ0KI2V4dHJhY3RpbmcgZGF0YSB3aXRoIGEgZGVwdGggb2YgbGVzcyB0aGFuIDVtDQpzdXJmYWNlID0gZGlzY3JldGVEQVRBW2Rpc2NyZXRlREFUQSREZXB0aCA8IDUsXQ0KDQojcGxvdHRpbmcgdGhlIGNvbnRvdXIgcGxvdA0KcCA9IHBsb3RfbHkoeD0gc3VyZmFjZSRJRCwgeSA9IHN1cmZhY2UkU3RhdGlvbiwgeiA9IHN1cmZhY2UkTk8zLjIsIA0KICAgICAgICB0eXBlID0gImNvbnRvdXIiKQ0KDQojYWRkaW5nIHRoZSBheGlzIGxhYmVscyBhbmQgdGl0bGUNCmxheW91dChwLCB4YXhpcyA9IGxpc3QodGl0bGUgPSAnQ3J1aXNlIG51bWJlcicpLCB5YXhpcyA9IGxpc3QodGl0bGUgPSAnU3RhdGlvbiBudW1iZXInKSwgdGl0bGUgPSAiTk8zLjIgKHVNKSIpDQpgYGANCg0KDQojIEIuIFZpc3VhbGl6YXRpb24gb2YgY29udGludW91cyBkYXRhIHVzaW5nIHNlY3Rpb24gcGxvdHMNCg0KSW4gdGhpcyBzZWN0aW9uLCB3ZSBhcmUgZ29pbmcgdG8gdmlzdWFsaXplIHNwYXRpYWwgY2hhbmdlcyBpbiB0ZXJtcyBvZiBkZXB0aCBhbmQgc3RhdGlvbiBmb3IgYSBnaXZlbiBjcnVpc2UuDQoNCiMjIEIxLiBJbXBvcnRpbmcgYW5kIHdyYW5nbGluZyBkYXRhDQoNCkZvciB0aGlzIHNlY3Rpb24sIHdlIGFyZSBnb2luZyB0byB1c2UgdGhlIGNzdiBmaWxlIHdlIG1hZGUgbGFzdCBkYXkgd2hpY2ggY29udGFpbnMgYWxsIHRoZSBjb250aW51b3VzIENURCBwcm9maWxlcywgYW5kIGV4dHJhY3Qgb3V0IG9uZSBjcnVpc2UuDQoNCmBgYHtyfQ0KI2ltcG9ydGluZyB0aGUgQ1REIGRhdGENCkNURGRhdGEgPC0gcmVhZC5jc3YoJ0NvbGJ5X2NydWlzZV9kYXRhXzIwMTItMjAxNy5jc3YnKQ0KDQojbWFraW5nIGEgbGlzdCBvZiB0aGUgZGF0ZXMgb2YgZWFjaCBjcnVpc2UNCmRhdGVzIDwtIHVuaXF1ZShDVERkYXRhW1snRGF0ZSddXSkNCg0KI2V4dHJhY3RpbmcgZGF0YSBmb3IgdGhlIGNydWlzZSBvbiBTZXB0ZW1iZXIgOHRoIDIwMTYNCmNydWlzZURhdGEgPC0gQ1REZGF0YVtDVERkYXRhW1snRGF0ZSddXSA9PSBkYXRlc1sxN10sXQ0KYGBgDQoNCldlIGNvdWxkIHVzZSB0aGUgc2FtZSBwbG90dGluZyBmdW5jdGlvbiBhcyBiZWZvcmUgdG8gcGxvdCBlLmcuIFRlbXBlcmF0dXJlOg0KDQpgYGB7cn0NCiMgcGxvdHRpbmcgdGhlIGNvbnRvdXIgcGxvdA0KcCA8LSBwbG90X2x5KHggPSBjcnVpc2VEYXRhJFN0YXRpb24sIHkgPSBjcnVpc2VEYXRhJERlcHRoLCB6ID0gY3J1aXNlRGF0YSRUZW1wZXJhdHVyZSwgdHlwZSA9ICJjb250b3VyIiwgY29udG91cnMgPSBsaXN0KHNob3dsaW5lcyA9IEZBTFNFKSkNCg0KI2FkZGluZyB0aGUgbGFiZWxzIGFuZCByZXZlcnNpbmcgdGhlIHktYXhpcw0KbGF5b3V0KHAseWF4aXMgPSBsaXN0KGF1dG9yYW5nZSA9ICJyZXZlcnNlZCIsdGl0bGUgPSAnRGVwdGggKG0pJyksDQogICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gJ1N0YXRpb24gbnVtYmVyJyksIA0KICAgICAgIHRpdGxlID0gIlRlbXBlcmF0dXJlIChkZWcgQykiKQ0KYGBgDQoNCldlIGVuZCB1cCB3aXRoIGRpc3RpbmN0IGJhbmRzIGF0IHRoZSBkZWVwZXIgZGVwdGhzLiBUaGlzIGlzIGJlY2F1c2Ugb2YgdGhlIGludGVycG9sYXRpb24gdGhhdCBoYXMgYmVlbiBkb25lIGJ5IHRoZSBwbG90dGluZyBmdW5jdGlvbi4gU3RhdGlvbnMgMSAtIDMgYXJlIDUwbSBvciBzaGFsbG93ZXIsIGhlbmNlIHRoZSBvbmx5IGRhdGEgYXQgdGhlIGRlZXAgZGVwdGhzIGFyZSBmcm9tIHN0YXRpb24gNC4gVGhlIHBsb3R0aW5nIGZ1bmN0aW9uIHRoZW4gYXNzdW1lcyB0aGF0IGlzIHRoZSB2YWx1ZSBhdCB0aGF0IGRlcHRoIGZvciBhbGwgc3RhdGlvbnMsIHdoaWNoIGlzIGluY29ycmVjdC4gTGV0J3MgdHJ5IGEgZGlmZmVyZW50IG1ldGhvZCBpbnN0ZWFkLg0KDQojIyBCMi4gQ29kaW5nIHRlY2huaXF1ZTogZm9yLWxvb3BzDQoNCldoZW4geW91IHdhbnQgdG8gcmVwZWF0IHRoZSBzYW1lIGJpdCBvZiBjb2RlIGEgY2VydGFpbiBudW1iZXIgb2YgdGltZXMsIGEgZm9yLWxvb3AgY2FuIGJlIHlvdXIgZnJpZW5kLiBGb3IgZXhhbXBsZSwgaWYgeW91IHdvdWxkIGxpa2UgdG8gcGxvdCBhIHNlY3Rpb24gZm9yIGVhY2ggY3J1aXNlLCByYXRoZXIgdGhhbiB0eXBlIG91dCB0aGUgY29kZSBmb3IgZWFjaCBjcnVpc2UgaW5kaXZpZHVhbGx5LCB3ZSBjYW4ganVzdCB3cml0ZSBpdCBvbmNlIGFuZCBpdGVyYXRlIG9yICpsb29wKiBvdmVyIHRoZSBjb2RlLiANCg0KTGV0J3Mgc3RhcnQgd2l0aCBhIHNpbXBsZSBleGFtcGxlOg0KDQojIyMjIEV4YW1wbGU6IHByaW50IHRoZSBzdGF0ZW1lbnQgImhlbGxvIiBmb3VyIHRpbWVzDQpgYGB7cn0NCmZvciAoaWkgaW4gMTo0KSB7DQogIHByaW50KCJoZWxsbyIpDQp9DQpgYGANCg0KIyMjIyBFeGFtcGxlOiBwcmludCB0aGUgc3RhdGVtZW50ICJoZWxsbyIgZm91ciB0aW1lcywgaW5jbHVkaW5nIHRoZSBudW1iZXIgYXQgdGhlIHN0YXJ0IG9mIHRoZSBzdGF0ZW1lbnQgZS5nLiAiMSBoZWxsbyINCmBgYHtyfQ0KZm9yIChpaSBpbiAxOjQpIHsNCiAgcHJpbnQocGFzdGUoaWksImhlbGxvIikpDQp9DQpgYGANCg0KIyMgQjMuIFBsb3R0aW5nIG9jZWFub2dyYXBoaWMgc2VjdGlvbg0KDQpGb3IgdGhpcyBtZXRob2QsIHdlJ2xsIG1ha2UgdXNlIG9mIHRoZSBmaWVsZHMgcGFja2FnZSwgd2hpY2ggcHJvdmlkZXMgdG9vbHMgZm9yIGFuYWx5emluZyBhbmQgdmlzdWFsaXppbmcgc3BhdGlhbCBkYXRhLg0KDQpgYGB7cn0NCmxpYnJhcnkoImZpZWxkcyIpDQpgYGANCg0KVG8gZG8gdGhpcyBwbG90LCB3ZSBhcmUgZ29pbnQgdG8gbmVlZCB0byBtYW5pcHVsYXRlIG91ciBkYXRhIGEgYml0IG1vcmUuIFdlIG5lZWQgdG8gbWFrZSBvdXIgVGVtcGVyYXR1cmUgZGF0YSBpbnRvIGEgbWF0cml4LCB3aGVyZSBlYWNoIHJvdyByZXByZXNlbnRzIGEgZGVwdGgsIGFuZCBlYWNoIGNvbHVtbiByZXByZXNlbnRzIGEgZGlmZmVyZW50IHN0YXRpb24uIFRoZSBkZXB0aCBkYXRhIGFyZSBub3QgY29uc2lzdGVudDsgdGhleSBhcmUgYWxsIGF0IGlycmVndWxhciBpbnRlcnZhbHMuIFRoZXJlZm9yZSwgdG8gcHV0IHRoZSB0ZW1wZXJhdHVyZSBkYXRhIGludG8gYSBtYXRyaXgsIHdlIGFyZSBnb2luZyB0byBuZWVkIHRvIGJpbiB0aGUgZGF0YSBpbnRvIHJlZ3VsYXIgZGVwdGggaW50ZXJ2YWxzIG9mIDFtLg0KDQpgYGB7cn0NCg0Kc3RhdGlvbkxhdCA8LSBjKDQzKzU0LjEzMC82MCwgNDMrNTEuOC82MCwgNDMrNDguNTYvNjAsIDQzKzQ0Ljg3LzYwKQ0KDQojY3JlYXRpbmcgYW4gZW1wdHkgbWF0cml4IHdpdGggMTAwIHJvd3MgKGkuZS4gZm9yIDEwMCBkZXB0aHMpIGFuZCA0IGNvbHVtbnMgKGkuZS4gb25lIGZvciBlYWNoIHN0YXRpb24pDQpURU0gPC0gbWF0cml4KE5BLG5yb3cgPSAxMDAsIG5jb2wgPSA0KQ0KDQojbG9vcGluZyB0aHJvdWdoIGVhY2ggc3RhdGlvbg0KZm9yIChzdCBpbiAxOjQpew0KICAjbG9vcGluZyB0aHJvdWdoIGVhY2ggZGVwdGggaW50ZXJ2YWwgKGZyb20gMW0gdG8gMTAwbSkNCiAgZm9yIChqIGluIDE6MTAwKXsNCiAgICAjZXh0cmFjdGluZyB0aGUgcmVsZXZhbnQgc3RhdGlvbiBmcm9tIHRoZSBjcnVpc2VEYXRhIGRhdGEgZnJhbWUNCiAgICBzdGF0aW9uRGF0YSA8LSBjcnVpc2VEYXRhW2NydWlzZURhdGEkU3RhdGlvbiA9PSBzdCxdDQogICAgDQogICAgI2Jpbm5lZCB0ZW1wZXJhdHVyZSB2YWx1ZSBmb3IgZ2l2ZW4gZGVwdGggaW50ZXJ2YWwNCiAgICB0ZW1wID0gbWVhbihzdGF0aW9uRGF0YVtjZWlsaW5nKHN0YXRpb25EYXRhJERlcHRoKT09aiwnVGVtcGVyYXR1cmUnXSkgDQogICAgDQogICAgI2Fzc2luZ2luZyB0aGUgYmlubmVkIHRlbXBlcmF0dXJlIHRvIHRoZSBqLXRoIHJvdyBhbmQgc3QtdGggY29sdW1uIG9mIHRoZSBURU0gbWF0cml4DQogICAgVEVNW2osc3RdIDwtIHRlbXANCiAgfQ0KfQ0KYGBgDQoNCk5vdyB3ZSd2ZSBjcmVhdGVkIG91ciBtYXRyaXgsIHdlIGNhbiBwbG90IHRoZSB0ZW1wZXJhdHVyZSBzZWN0aW9uLg0KDQpgYGB7cn0NCmltYWdlLnBsb3QoeD1zdGF0aW9uTGF0WzQ6MV0seT0tMTAwOi0xLHQoVEVNWzEwMDoxLDQ6MV0pLA0KICAgICAgICAgICB6bGltPWMoOCwyMCksDQogICAgICAgICAgIGNvbD10aW0uY29sb3JzKDI0KSwNCiAgICAgICAgICAgeGxhYj0nTGF0aXR1ZGUgKGRlZyBOKScsDQogICAgICAgICAgIHlsYWI9J0RlcHRoIChtKScsDQogICAgICAgICAgIG1haW49J0NydWlzZSAyMDE2MDkwOCcsDQogICAgICAgICAgIGxlZ2VuZC5sYWI9J1RlbXBlcmF0dXJlIChDKScsDQpsZWdlbmQubGluZT0yLjUpDQoNCmBgYA0KDQojIyMjIEV4YW1wbGU6IEhvdyBkbyB3ZSBjaGFuZ2UgdGhlIGNvbG9yIHNjaGVtZT8NCg0KMS4gV2UgY2FuIHVzZSBvbmUgb2YgdGhlIFIgY29sb3IgcGFsZXR0ZXMgZS5nLiBgaGVhdC5jb2xvcnNgLCBgdGVycmFpbi5jb2xvcnNgLCBgdG9wby5jb2xvcnNgIGFzIHRoZSBgY29sYCBhcmd1bWVudCBpbiBwbGFjZSBvZiB0aGUgYHRpbS5jb2xvcnNgIGFyZ3VtZW50LiANCjIuIFdlIGNhbiB1c2Ugb25lIG9mIHRoZSBDb2xvciBCcmV3ZXIgcGFsZXR0ZXMuIENvbG9yIEJyZXdlciB3YXMgYSBwcm9qZWN0IHdoaWNoIGNyZWF0ZWQgYSBsb3Qgb2YgZGlmZmVyZW50IGNvbG9yIHBhbGV0dGVzIGZvciB0aGVtYXRpYyBtYXBzLiBUaGVyZSBhcmUgZGlmZmVyZW50IHR5cGVzIG9mIGNvbG9yIHBhbGV0dGVzIGRlcGVuZGluZyBvbiB5b3VyIG5lZWRzIChlLmcuIHNlcXVlbnRpYWwgY29sb3Igc2NhbGUsIGRpdmVyZ2luZyBjb2xvciBzY2FsZSwgcXVhbnRhdGl2ZSBzY2FsZXMpLiBJdCBoYXMgYSBjb29sIHdlYi1pbnRlcmZhY2UgKGh0dHA6Ly9jb2xvcmJyZXdlcjIub3JnLyMpIHdoZXJlIHlvdSBjYW4gcGxheSBhcm91bmQgd2l0aCB0aGUgcGFsZXR0ZXMuIFdoYXQgaXMgZ29vZCBhYm91dCBDb2xvciBCcmV3ZXIgaXMgdGhlIHNlcXVlbnRpYWwgY29sb3IgcGFsZXR0ZXMgKHRoZSB0eXBlIHdlIHVzZWQgaW4gb3VyIGFib3ZlIHNlY3Rpb24gcGxvdCkgYXJlIG1hZGUgZnJvbSBhdCBtb3N0IDMgY29sb3JzLCBhbmQgYXJlIGFsdGVyZWQgYnkgY2hhbmdpbmcgdGhlIGh1ZS4gVGhpcyBtYWtlcyB0aGUgbWFwcyBjb2xvcmJsaW5kLWZyaWVuZGx5IGFuZCBwcmV2ZW50cyBhcnRpZmljaWFsIHNoYXJwIGVkZ2VzIGJldHdlZW4gY29sb3IgY2hhbmdlcy4gUiBoYXMgYSBwYWNrYWdlIGZvciB0aGUgQ29sb3IgQnJld2VyIHBhbGV0dGVzLiBDaGVjayBvdXQgdGhlIGhlbHAgdG8gc2VlIGEgbGlzdCBvZiB0aGUgc2VxdWVudGlhbCBwYWxldHRlIG5hbWVzIHlvdSBjYW4gdXNlLg0KDQoNCmBgYHtyfQ0KbGlicmFyeSgiUkNvbG9yQnJld2VyIikNCmBgYA0KDQpgYGB7cn0NCg0KY29scGFsIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg5LCdZbE9yUmQnKSkgICAjIG1ha2UgY29sb3JzDQoNCmltYWdlLnBsb3QoeD1zdGF0aW9uTGF0WzQ6MV0seT0tMTAwOi0xLHQoVEVNWzEwMDoxLDQ6MV0pLA0KICAgICAgICAgICB6bGltPWMoOCwyMCksDQogICAgICAgICAgIGNvbD1jb2xwYWwoNjApLA0KICAgICAgICAgICB4bGFiPSdTdGF0aW9uJywNCiAgICAgICAgICAgeWxhYj0nRGVwdGggKG0pJywNCiAgICAgICAgICAgbWFpbj0nQ3J1aXNlIDIwMTYwOTA4JywNCiAgICAgICAgICAgbGVnZW5kLmxhYj0nVGVtcGVyYXR1cmUgKEMpJywNCmxlZ2VuZC5saW5lPTIuNSkNCmBgYA0KDQojIyBCNC4gQ29kaW5nIHRlY2huaXF1ZTogRnVuY3Rpb25zDQoNCkZ1bmN0aW9ucyBhcmUgYmxvY2tzIG9mIGNvZGUgd2hpY2ggd2hlbiBjYWxsZWQsIHBlcmZvcm0gYSBzcGVjaWZpYyB0YXNrLiBVc3VhbGx5IHlvdSBnaXZlIHRoZW0gYW4gaW5wdXQgYW5kIHRoZXkgZ2l2ZSB5b3UgYW4gb3V0cHV0LiBXZSd2ZSB1c2VkIGxvdHMgb2YgZGlmZmVyZW50IFIgaW4tYnVpbHQgZnVuY3Rpb25zIGUuZy4gYHJlYWQuY3N2YCwgYGltYWdlLnBsb3RgLCBldGMuIFdlIGNhbiB3cml0ZSBvdXIgb3duIGZ1bmN0aW9ucyBmb3Igb3VyIG93biBzcGVjaWZpYyB0YXNrcy4NCg0KIyMjIyBFeGFtcGxlOiB3cml0ZSBhIGZ1bmN0aW9uIHdoaWNoIGFkZHMgdHdvIG51bWJlcnMNCg0KYGBge3J9DQphZGRpdGlvbiA8LSBmdW5jdGlvbihhLGIpew0KICByZXR1cm4oYStiKQ0KfQ0KDQphZGRpdGlvbig5LDMpDQpgYGANCg0KTGV0J3Mgd3JpdGUgYSBmdW5jdGlvbiB3aGljaCB0dXJucyBhIHZhcmlhYmxlIGZyb20gdGhlIENURGRhdGEgaW50byBhIG1hdHJpeCAoZm9yIHBsb3R0aW5nIGFzIGEgc2VnbWVudCkuIFRvIGRvIHRoaXMsIHdlJ2xsIGp1c3QgY29weSB0aGUgY29kZSBmcm9tIGFib3ZlIGFuZCB3cmFwIGl0IGluIGEgZnVuY3Rpb24uDQoNCmBgYHtyfQ0KY29sMm1hdHJpeCA8LSBmdW5jdGlvbihjb2x1bW5OYW1lKXsNCiAgDQogICNjcmVhdGluZyBhbiBlbXB0eSBtYXRyaXggd2l0aCAxMDAgcm93cyAoaS5lLiBmb3IgMTAwIGRlcHRocykgYW5kIDQgY29sdW1ucyAoaS5lLiBvbmUgZm9yIGVhY2ggc3RhdGlvbikNCiAgVEVNIDwtIG1hdHJpeChOQSxucm93ID0gMTAwLCBuY29sID0gNCkNCiAgDQogICNsb29waW5nIHRocm91Z2ggZWFjaCBzdGF0aW9uDQogIGZvciAoc3QgaW4gMTo0KXsNCiAgICAjbG9vcGluZyB0aHJvdWdoIGVhY2ggZGVwdGggaW50ZXJ2YWwgKGZyb20gMW0gdG8gMTAwbSkNCiAgICBmb3IgKGogaW4gMToxMDApew0KICAgICAgI2V4dHJhY3RpbmcgdGhlIHJlbGV2YW50IHN0YXRpb24gZnJvbSB0aGUgY3J1aXNlRGF0YSBkYXRhIGZyYW1lDQogICAgICBzdGF0aW9uRGF0YSA8LSBjcnVpc2VEYXRhW2NydWlzZURhdGEkU3RhdGlvbiA9PSBzdCxdDQogICAgICANCiAgICAgICNiaW5uZWQgdGVtcGVyYXR1cmUgdmFsdWUgZm9yIGdpdmVuIGRlcHRoIGludGVydmFsDQogICAgICB0ZW1wID0gbWVhbihzdGF0aW9uRGF0YVtjZWlsaW5nKHN0YXRpb25EYXRhJERlcHRoKT09aixjb2x1bW5OYW1lXSkgDQogICAgICANCiAgICAgICNhc3NpbmdpbmcgdGhlIGJpbm5lZCB0ZW1wZXJhdHVyZSB0byB0aGUgai10aCByb3cgYW5kIHN0LXRoIGNvbHVtbiBvZiB0aGUgVEVNIG1hdHJpeA0KICAgICAgVEVNW2osc3RdIDwtIHRlbXANCiAgICB9DQogIH0NCiAgcmV0dXJuKFRFTSkNCn0NCg0KYGBgDQoNCg0KDQojIEFzc2lnbm1lbnQgKGluIGxhYikNCg0KMS4gIGEuIFBsb3QgYSBjb250b3VyIHBsb3QgZm9yIGRpZmZlcmVudCBkaXNjcmV0ZSB2YXJpYWJsZXMgKHVzZSB0aGUgYGNvbDJtYXRyaXhgIGZ1bmN0aW9uIHdlIGp1c3Qgd3JvdGUgdG8gd3JhbmdsZSB5b3VyIGRhdGEgaW50byB0aGUgY29ycmVjdCBmb3JtYXQpLiBDYW4geW91IGZpZ3VyZSBvdXQgaG93IHRvIGNoYW5nZSB0aGUgY29sb3Igc2NoZW1lPyANCiAgICBiLiBUcnkgcGxvdHRpbmcgYSBzdGF0aW9uLWJ5LWRlcHRoIGNvbnRvdXIgcGxvdCBmb3IgMSBjcnVpc2UgKGluc3RlYWQgb2Ygc3RhdGlvbi1ieS1jcnVpc2UpDQogICAgYy4gVHJ5IHBsb3R0aW5nIGEgZGVwdGgtYnktY3J1aXNlIGNvbnRvdXIgcGxvdCBmb3IgMSBzdGF0aW9uLg0KICAgIGQuIFRyeSBwbG90dGluZyBhIGNvbnRvdXIgcGxvdCBvZiB5b3VyIGNob2ljZSBmb3IgYSBkaWZmZXJlbnQgY3J1aXNlLg0KMi4gUGxvdCBhbiBvY2Vhbm9ncmFwaGljIHNlY3Rpb24gZm9yIGRpZmZlcmVudCB2YXJpYWJsZXMgZnJvbSB0aGUgQ1REIGNhc3RzLiBSZW1lbWJlciB0byBjaGFuZ2UgdGhlIGxpbWl0cyBvZiB0aGUgY29sb3Igc2NhbGUgYnkgYWRqdXN0aW5nIHRoZSBgemxpbWAgYXJndW1lbnQgdG8gYGltYWdlLnBsb3RgLg0KDQoNCg==
======= Lab 3: Visualizing 2D patterns in oceanographic cruise data

This lab focuses on visualizing temporal and spatial patterns in oceanographic cruise data i.e. how do parameters vary upriver compared with the open ocean or how do parameters vary with depth or how does one station change over the season? The tools you are introduced to here can be used to graph and analyze data in your labs, your independent research projects and the cruise data gathered throughout the semester. Be sure to save any scripts that you develop so you can continue to use them.

A. Visualization of discrete data using contour plots

In this section, we are going to visualize how parameters vary at each station for each cruise.

A1. Importing data

We are going to look at some of the discrete data, taken from the Niskin bottles. To do this, we need to create another csv file from the Colby_cruise_data_2012-2017.xlsx sheet like last week. But let’s start by setting our working directory.

setwd('C:/Users/Catherine/Documents/REUColbyCoding/CMdev/RbigelowCMdev/Lab03_2018')

Creating discrete data csv file

  1. Open Colby_cruise_data_2012-2017.xlsx
  2. Open a new blank Excel file
  3. Go to the “discrete data” tab
  4. Select and copy the following columns: date, cruise, station, depth, SiO4, NO3+2, PO4, NH4, Bacteria Conc, Viral Conc, Chl Total, CHL <20um, CHL<3um, Flowcam Biomass.
  5. Paste the columns into the blank Excel file
  6. Delete the rows from 2012 - 2015 and 2017 i.e. so the only year left is 2016.
  7. Delete the dates column and the top two rows (the row of units and the row contain the units of a few of the columns)
  8. Press CTRL-F on Windows, or the Command-F on a Mac, to bring up the “Find and Replace” window.
  9. Go to the Replace tab, enter “Cruise” in the “Find What” box and nothing in the “Replace with” box, hit “Replace all”
  10. Repeat 9 for the word “BLOS” and close the window
  11. Save the file as a CSV (Comma Delimited) with a sensible name e.g. Colby_discrete_data_2016.csv

Importing the data

Let’s import the data as before.

# read in the whole csv file
discreteDATA <- read.csv('Colby_discrete_data_2016.csv', header = TRUE)

A2. Data wrangling and creating contour plots

We are going to create a contour plot for the surface data, for station vs cruise. To do this we are going to use the plotly library, so let’s import the package, and load it into our workspace

install.packages("plotly")

library("plotly")

Now we can extract the surface data from our DATA data frame and plot the result.

#extracting data with a depth of less than 5m
surface = discreteDATA[discreteDATA$Depth < 5,]
#plotting the contour plot
p = plot_ly(x= surface$ID, y = surface$Station, z = surface$NO3.2, 
        type = "contour")
#adding the axis labels and title
layout(p, xaxis = list(title = 'Cruise number'), yaxis = list(title = 'Station number'), title = "NO3.2 (uM)")

B. Visualization of continuous data using section plots

In this section, we are going to visualize spatial changes in terms of depth and station for a given cruise.

B1. Importing and wrangling data

For this section, we are going to use the csv file we made last day which contains all the continuous CTD profiles, and extract out one cruise.

#importing the CTD data
CTDdata <- read.csv('Colby_cruise_data_2012-2017.csv')
#making a list of the dates of each cruise
dates <- unique(CTDdata[['Date']])
#extracting data for the cruise on September 8th 2016
cruiseData <- CTDdata[CTDdata[['Date']] == 20160908,]
#extracting station 4 from the cruiseData dataframe
stationData <- cruiseData[cruiseData$Station == 4,]

We could use the same plotting function as before to plot e.g. Temperature:

# plotting the contour plot
p <- plot_ly(x = cruiseData$Station, y = cruiseData$Depth, z = cruiseData$Temperature, type = "contour", contours = list(showlines = FALSE))
#adding the labels and reversing the y-axis
layout(p,yaxis = list(autorange = "reversed",title = 'Depth (m)'),
       xaxis = list(title = 'Station number'), 
       title = "Temperature (deg C)")

We end up with distinct bands at the deeper depths. This is because of the interpolation that has been done by the plotting function. Stations 1 - 3 are 50m or shallower, hence the only data at the deep depths are from station 4. The plotting function then assumes that is the value at that depth for all stations, which is incorrect. Let’s try a different method instead.

B2. Coding technique: for-loops

When you want to repeat the same bit of code multiple times, a for-loop can be your friend. For example, if you would like to plot a section for each cruise, rather than type out the code for each cruise individually, we can just write it once and iterate or loop over the code.

Let’s start with a simple example:

Example: print the statement “hello” four times

for (ii in 1:4) {
  print("hello")
}
[1] "hello"
[1] "hello"
[1] "hello"
[1] "hello"

Example: print the statement “hello” four times, including the number at the start of the statement e.g. “1 hello”

for (ii in 1:4) {
  print(paste(ii,"hello"))
}
[1] "1 hello"
[1] "2 hello"
[1] "3 hello"
[1] "4 hello"

B3. Plotting oceanographic section

For this method, we’ll make use of the fields package, which provides tools for analyzing and visualizing spatial data.

library("fields")

To do this plot, we are goint to need to manipulate our data a bit more. We need to make our Temperature data into a matrix, where each row represents a depth, and each column represents a different station. The depth data are not consistent; they are all at irregular intervals. Therefore, to put the temperature data into a matrix, we are going to need to bin the data into regular depth intervals of 1m.

#stationLat <- c(43+54.130/60, 43+51.8/60, 43+48.56/60, 43+44.87/60)
#creating an empty matrix with 100 rows (i.e. for 100 depths) and 4 columns (i.e. one for each station)
TEM <- matrix(NA,nrow = 100, ncol = 4)
#looping through each station
for (st in 1:4){
  #looping through each depth interval (from 1m to 100m)
  for (j in 1:100){
    #extracting the relevant station from the cruiseData data frame
    stationData <- cruiseData[cruiseData$Station == st,]
    
    #binned temperature value for given depth interval
    temp = mean(stationData[ceiling(stationData$Depth)==j,'Temperature']) 
    
    #assinging the binned temperature to the j-th row and st-th column of the TEM matrix
    TEM[j,st] <- temp
  }
}

Now we’ve created our matrix, we can plot the temperature section.

image.plot(x=1:4,y=-100:-1,t(TEM[100:1,4:1]),
           zlim=c(8,20),
           col=tim.colors(24),
           xlab='station',
           ylab='Depth (m)',
           main='Cruise 20160908',
           legend.lab='Temperature (C)',
legend.line=2.5)

Example: How do we change the color scheme?

  1. We can use one of the R color palettes e.g. heat.colors, terrain.colors, topo.colors as the col argument in place of the tim.colors argument.
  2. We can use one of the Color Brewer palettes. Color Brewer was a project which created a lot of different color palettes for thematic maps. There are different types of color palettes depending on your needs (e.g. sequential color scale, diverging color scale, quantative scales). It has a cool web-interface (http://colorbrewer2.org/#) where you can play around with the palettes. What is good about Color Brewer is the sequential color palettes (the type we used in our above section plot) are made from at most 3 colors, and are altered by changing the hue. This makes the maps colorblind-friendly and prevents artificial sharp edges between color changes. R has a package for the Color Brewer palettes. Check out the help to see a list of the sequential palette names you can use.
library("RColorBrewer")
colpal <- colorRampPalette(brewer.pal(9,'YlOrRd'))   # make colors
image.plot(x=1:4,y=-100:-1,t(TEM[100:1,4:1]),
           zlim=c(8,20),
           col=colpal(60),
           xlab='Station',
           ylab='Depth (m)',
           main='Cruise 20160908',
           legend.lab='Temperature (C)',
legend.line=2.5)

3. Assignment (in lab)

  1. Plot a contour plot for different discrete variables. Can you figure out how to change the color scheme?

  2. Plot an oceanographic section for different variables from the CTD casts. Remember to change the limits of the color scale by adjusting the zlim argument to image.plot.

LS0tDQp0aXRsZTogIkxhYiAzOiBWaXN1YWxpemluZyAyRCBwYXR0ZXJucyBpbiBvY2Vhbm9ncmFwaGljIGNydWlzZSBkYXRhIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KVGhpcyBsYWIgZm9jdXNlcyBvbiB2aXN1YWxpemluZyB0ZW1wb3JhbCBhbmQgc3BhdGlhbCBwYXR0ZXJucyBpbiBvY2Vhbm9ncmFwaGljIGNydWlzZSBkYXRhIGkuZS4gaG93IGRvIHBhcmFtZXRlcnMgdmFyeSB1cHJpdmVyIGNvbXBhcmVkIHdpdGggdGhlIG9wZW4gb2NlYW4gb3IgaG93IGRvIHBhcmFtZXRlcnMgdmFyeSB3aXRoIGRlcHRoIG9yIGhvdyBkb2VzIG9uZSBzdGF0aW9uIGNoYW5nZSBvdmVyIHRoZSBzZWFzb24/IFRoZSB0b29scyB5b3UgYXJlIGludHJvZHVjZWQgdG8gaGVyZSBjYW4gYmUgdXNlZCB0byBncmFwaCBhbmQgYW5hbHl6ZSBkYXRhIGluIHlvdXIgbGFicywgeW91ciBpbmRlcGVuZGVudCByZXNlYXJjaCBwcm9qZWN0cyBhbmQgdGhlIGNydWlzZSBkYXRhIGdhdGhlcmVkIHRocm91Z2hvdXQgdGhlIHNlbWVzdGVyLiBCZSBzdXJlIHRvIHNhdmUgYW55IHNjcmlwdHMgdGhhdCB5b3UgZGV2ZWxvcCBzbyB5b3UgY2FuIGNvbnRpbnVlIHRvIHVzZSB0aGVtLg0KDQojIEEuIFZpc3VhbGl6YXRpb24gb2YgZGlzY3JldGUgZGF0YSB1c2luZyBjb250b3VyIHBsb3RzDQoNCkluIHRoaXMgc2VjdGlvbiwgd2UgYXJlIGdvaW5nIHRvIHZpc3VhbGl6ZSBob3cgcGFyYW1ldGVycyB2YXJ5IGF0IGVhY2ggc3RhdGlvbiBmb3IgZWFjaCBjcnVpc2UuDQoNCiMjIEExLiBJbXBvcnRpbmcgZGF0YQ0KDQpXZSBhcmUgZ29pbmcgdG8gbG9vayBhdCBzb21lIG9mIHRoZSBkaXNjcmV0ZSBkYXRhLCB0YWtlbiBmcm9tIHRoZSBOaXNraW4gYm90dGxlcy4gVG8gZG8gdGhpcywgd2UgbmVlZCB0byBjcmVhdGUgYW5vdGhlciBjc3YgZmlsZSBmcm9tIHRoZSBDb2xieV9jcnVpc2VfZGF0YV8yMDEyLTIwMTcueGxzeCBzaGVldCBsaWtlIGxhc3Qgd2Vlay4gQnV0IGxldCdzIHN0YXJ0IGJ5IHNldHRpbmcgb3VyIHdvcmtpbmcgZGlyZWN0b3J5Lg0KDQpgYGB7cn0NCnNldHdkKCdDOi9Vc2Vycy9DYXRoZXJpbmUvRG9jdW1lbnRzL1JFVUNvbGJ5Q29kaW5nL0NNZGV2L1JiaWdlbG93Q01kZXYvTGFiMDNfMjAxOCcpDQpgYGANCg0KIyMjIENyZWF0aW5nIGRpc2NyZXRlIGRhdGEgY3N2IGZpbGUNCg0KMS4gT3BlbiBDb2xieV9jcnVpc2VfZGF0YV8yMDEyLTIwMTcueGxzeA0KMi4gT3BlbiBhIG5ldyBibGFuayBFeGNlbCBmaWxlDQoyLiBHbyB0byB0aGUgImRpc2NyZXRlIGRhdGEiIHRhYg0KMy4gU2VsZWN0IGFuZCBjb3B5IHRoZSBmb2xsb3dpbmcgY29sdW1uczogZGF0ZSwgY3J1aXNlLCBzdGF0aW9uLCBkZXB0aCwgU2lPNCwJTk8zKzIsCVBPNCwJTkg0LAlCYWN0ZXJpYSBDb25jLAlWaXJhbCBDb25jLAlDaGwgVG90YWwsCUNITCA8MjB1bSwJQ0hMPDN1bSwJRmxvd2NhbSBCaW9tYXNzLg0KNS4gUGFzdGUgdGhlIGNvbHVtbnMgaW50byB0aGUgYmxhbmsgRXhjZWwgZmlsZQ0KNi4gRGVsZXRlIHRoZSByb3dzIGZyb20gMjAxMiAtIDIwMTUgYW5kIDIwMTcgaS5lLiBzbyB0aGUgb25seSB5ZWFyIGxlZnQgaXMgMjAxNi4NCjcuIERlbGV0ZSB0aGUgZGF0ZXMgY29sdW1uIGFuZCB0aGUgdG9wIHR3byByb3dzICh0aGUgcm93IG9mIHVuaXRzIGFuZCB0aGUgcm93IGNvbnRhaW4gdGhlIHVuaXRzIG9mIGEgZmV3IG9mIHRoZSBjb2x1bW5zKQ0KOC4gUHJlc3MgQ1RSTC1GIG9uIFdpbmRvd3MsIG9yIHRoZSBDb21tYW5kLUYgb24gYSBNYWMsIHRvIGJyaW5nIHVwIHRoZSAiRmluZCBhbmQgUmVwbGFjZSIgd2luZG93Lg0KOS4gR28gdG8gdGhlIFJlcGxhY2UgdGFiLCBlbnRlciAiQ3J1aXNlIiBpbiB0aGUgIkZpbmQgV2hhdCIgYm94IGFuZCBub3RoaW5nIGluIHRoZSAiUmVwbGFjZSB3aXRoIiBib3gsIGhpdCAiUmVwbGFjZSBhbGwiDQoxMC4gUmVwZWF0IDkgZm9yIHRoZSB3b3JkICJCTE9TIiBhbmQgY2xvc2UgdGhlIHdpbmRvdw0KMTEuIFNhdmUgdGhlIGZpbGUgYXMgYSBDU1YgKENvbW1hIERlbGltaXRlZCkgd2l0aCBhIHNlbnNpYmxlIG5hbWUgZS5nLiBDb2xieV9kaXNjcmV0ZV9kYXRhXzIwMTYuY3N2DQoNCiMjIyBJbXBvcnRpbmcgdGhlIGRhdGENCg0KTGV0J3MgaW1wb3J0IHRoZSBkYXRhIGFzIGJlZm9yZS4NCg0KYGBge3J9DQojIHJlYWQgaW4gdGhlIHdob2xlIGNzdiBmaWxlDQpkaXNjcmV0ZURBVEEgPC0gcmVhZC5jc3YoJ0NvbGJ5X2Rpc2NyZXRlX2RhdGFfMjAxNi5jc3YnLCBoZWFkZXIgPSBUUlVFKQ0KYGBgDQoNCiMjIEEyLiBEYXRhIHdyYW5nbGluZyBhbmQgY3JlYXRpbmcgY29udG91ciBwbG90cw0KDQpXZSBhcmUgZ29pbmcgdG8gY3JlYXRlIGEgY29udG91ciBwbG90IGZvciB0aGUgc3VyZmFjZSBkYXRhLCBmb3Igc3RhdGlvbiB2cyBjcnVpc2UuIFRvIGRvIHRoaXMgd2UgYXJlIGdvaW5nIHRvIHVzZSB0aGUgYHBsb3RseWAgbGlicmFyeSwgc28gbGV0J3MgaW1wb3J0IHRoZSBwYWNrYWdlLCBhbmQgbG9hZCBpdCBpbnRvIG91ciB3b3Jrc3BhY2UNCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KDQpsaWJyYXJ5KCJwbG90bHkiKQ0KYGBgDQoNCk5vdyB3ZSBjYW4gZXh0cmFjdCB0aGUgc3VyZmFjZSBkYXRhIGZyb20gb3VyIGBEQVRBYCBkYXRhIGZyYW1lIGFuZCBwbG90IHRoZSByZXN1bHQuDQoNCmBgYHtyfQ0KI2V4dHJhY3RpbmcgZGF0YSB3aXRoIGEgZGVwdGggb2YgbGVzcyB0aGFuIDVtDQpzdXJmYWNlID0gZGlzY3JldGVEQVRBW2Rpc2NyZXRlREFUQSREZXB0aCA8IDUsXQ0KDQojcGxvdHRpbmcgdGhlIGNvbnRvdXIgcGxvdA0KcCA9IHBsb3RfbHkoeD0gc3VyZmFjZSRJRCwgeSA9IHN1cmZhY2UkU3RhdGlvbiwgeiA9IHN1cmZhY2UkTk8zLjIsIA0KICAgICAgICB0eXBlID0gImNvbnRvdXIiKQ0KDQojYWRkaW5nIHRoZSBheGlzIGxhYmVscyBhbmQgdGl0bGUNCmxheW91dChwLCB4YXhpcyA9IGxpc3QodGl0bGUgPSAnQ3J1aXNlIG51bWJlcicpLCB5YXhpcyA9IGxpc3QodGl0bGUgPSAnU3RhdGlvbiBudW1iZXInKSwgdGl0bGUgPSAiTk8zLjIgKHVNKSIpDQpgYGANCg0KDQojIEIuIFZpc3VhbGl6YXRpb24gb2YgY29udGludW91cyBkYXRhIHVzaW5nIHNlY3Rpb24gcGxvdHMNCg0KSW4gdGhpcyBzZWN0aW9uLCB3ZSBhcmUgZ29pbmcgdG8gdmlzdWFsaXplIHNwYXRpYWwgY2hhbmdlcyBpbiB0ZXJtcyBvZiBkZXB0aCBhbmQgc3RhdGlvbiBmb3IgYSBnaXZlbiBjcnVpc2UuDQoNCiMjIEIxLiBJbXBvcnRpbmcgYW5kIHdyYW5nbGluZyBkYXRhDQoNCkZvciB0aGlzIHNlY3Rpb24sIHdlIGFyZSBnb2luZyB0byB1c2UgdGhlIGNzdiBmaWxlIHdlIG1hZGUgbGFzdCBkYXkgd2hpY2ggY29udGFpbnMgYWxsIHRoZSBjb250aW51b3VzIENURCBwcm9maWxlcywgYW5kIGV4dHJhY3Qgb3V0IG9uZSBjcnVpc2UuDQoNCmBgYHtyfQ0KI2ltcG9ydGluZyB0aGUgQ1REIGRhdGENCkNURGRhdGEgPC0gcmVhZC5jc3YoJ0NvbGJ5X2NydWlzZV9kYXRhXzIwMTItMjAxNy5jc3YnKQ0KDQojbWFraW5nIGEgbGlzdCBvZiB0aGUgZGF0ZXMgb2YgZWFjaCBjcnVpc2UNCmRhdGVzIDwtIHVuaXF1ZShDVERkYXRhW1snRGF0ZSddXSkNCg0KI2V4dHJhY3RpbmcgZGF0YSBmb3IgdGhlIGNydWlzZSBvbiBTZXB0ZW1iZXIgOHRoIDIwMTYNCmNydWlzZURhdGEgPC0gQ1REZGF0YVtDVERkYXRhW1snRGF0ZSddXSA9PSAyMDE2MDkwOCxdDQpgYGANCg0KV2UgY291bGQgdXNlIHRoZSBzYW1lIHBsb3R0aW5nIGZ1bmN0aW9uIGFzIGJlZm9yZSB0byBwbG90IGUuZy4gVGVtcGVyYXR1cmU6DQoNCmBgYHtyfQ0KIyBwbG90dGluZyB0aGUgY29udG91ciBwbG90DQpwIDwtIHBsb3RfbHkoeCA9IGNydWlzZURhdGEkU3RhdGlvbiwgeSA9IGNydWlzZURhdGEkRGVwdGgsIHogPSBjcnVpc2VEYXRhJFRlbXBlcmF0dXJlLCB0eXBlID0gImNvbnRvdXIiLCBjb250b3VycyA9IGxpc3Qoc2hvd2xpbmVzID0gRkFMU0UpKQ0KDQojYWRkaW5nIHRoZSBsYWJlbHMgYW5kIHJldmVyc2luZyB0aGUgeS1heGlzDQpsYXlvdXQocCx5YXhpcyA9IGxpc3QoYXV0b3JhbmdlID0gInJldmVyc2VkIix0aXRsZSA9ICdEZXB0aCAobSknKSwNCiAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAnU3RhdGlvbiBudW1iZXInKSwgDQogICAgICAgdGl0bGUgPSAiVGVtcGVyYXR1cmUgKGRlZyBDKSIpDQpgYGANCg0KV2UgZW5kIHVwIHdpdGggZGlzdGluY3QgYmFuZHMgYXQgdGhlIGRlZXBlciBkZXB0aHMuIFRoaXMgaXMgYmVjYXVzZSBvZiB0aGUgaW50ZXJwb2xhdGlvbiB0aGF0IGhhcyBiZWVuIGRvbmUgYnkgdGhlIHBsb3R0aW5nIGZ1bmN0aW9uLiBTdGF0aW9ucyAxIC0gMyBhcmUgNTBtIG9yIHNoYWxsb3dlciwgaGVuY2UgdGhlIG9ubHkgZGF0YSBhdCB0aGUgZGVlcCBkZXB0aHMgYXJlIGZyb20gc3RhdGlvbiA0LiBUaGUgcGxvdHRpbmcgZnVuY3Rpb24gdGhlbiBhc3N1bWVzIHRoYXQgaXMgdGhlIHZhbHVlIGF0IHRoYXQgZGVwdGggZm9yIGFsbCBzdGF0aW9ucywgd2hpY2ggaXMgaW5jb3JyZWN0LiBMZXQncyB0cnkgYSBkaWZmZXJlbnQgbWV0aG9kIGluc3RlYWQuDQoNCiMjIEIyLiBDb2RpbmcgdGVjaG5pcXVlOiBmb3ItbG9vcHMNCg0KV2hlbiB5b3Ugd2FudCB0byByZXBlYXQgdGhlIHNhbWUgYml0IG9mIGNvZGUgbXVsdGlwbGUgdGltZXMsIGEgZm9yLWxvb3AgY2FuIGJlIHlvdXIgZnJpZW5kLiBGb3IgZXhhbXBsZSwgaWYgeW91IHdvdWxkIGxpa2UgdG8gcGxvdCBhIHNlY3Rpb24gZm9yIGVhY2ggY3J1aXNlLCByYXRoZXIgdGhhbiB0eXBlIG91dCB0aGUgY29kZSBmb3IgZWFjaCBjcnVpc2UgaW5kaXZpZHVhbGx5LCB3ZSBjYW4ganVzdCB3cml0ZSBpdCBvbmNlIGFuZCBpdGVyYXRlIG9yICpsb29wKiBvdmVyIHRoZSBjb2RlLiANCg0KTGV0J3Mgc3RhcnQgd2l0aCBhIHNpbXBsZSBleGFtcGxlOg0KDQojIyMjIEV4YW1wbGU6IHByaW50IHRoZSBzdGF0ZW1lbnQgImhlbGxvIiBmb3VyIHRpbWVzDQpgYGB7cn0NCmZvciAoaWkgaW4gMTo0KSB7DQogIHByaW50KCJoZWxsbyIpDQp9DQpgYGANCg0KIyMjIyBFeGFtcGxlOiBwcmludCB0aGUgc3RhdGVtZW50ICJoZWxsbyIgZm91ciB0aW1lcywgaW5jbHVkaW5nIHRoZSBudW1iZXIgYXQgdGhlIHN0YXJ0IG9mIHRoZSBzdGF0ZW1lbnQgZS5nLiAiMSBoZWxsbyINCmBgYHtyfQ0KZm9yIChpaSBpbiAxOjQpIHsNCiAgcHJpbnQocGFzdGUoaWksImhlbGxvIikpDQp9DQpgYGANCg0KIyMgQjMuIFBsb3R0aW5nIG9jZWFub2dyYXBoaWMgc2VjdGlvbg0KDQpGb3IgdGhpcyBtZXRob2QsIHdlJ2xsIG1ha2UgdXNlIG9mIHRoZSBmaWVsZHMgcGFja2FnZSwgd2hpY2ggcHJvdmlkZXMgdG9vbHMgZm9yIGFuYWx5emluZyBhbmQgdmlzdWFsaXppbmcgc3BhdGlhbCBkYXRhLg0KDQpgYGB7cn0NCmxpYnJhcnkoImZpZWxkcyIpDQpgYGANCg0KVG8gZG8gdGhpcyBwbG90LCB3ZSBhcmUgZ29pbnQgdG8gbmVlZCB0byBtYW5pcHVsYXRlIG91ciBkYXRhIGEgYml0IG1vcmUuIFdlIG5lZWQgdG8gbWFrZSBvdXIgVGVtcGVyYXR1cmUgZGF0YSBpbnRvIGEgbWF0cml4LCB3aGVyZSBlYWNoIHJvdyByZXByZXNlbnRzIGEgZGVwdGgsIGFuZCBlYWNoIGNvbHVtbiByZXByZXNlbnRzIGEgZGlmZmVyZW50IHN0YXRpb24uIFRoZSBkZXB0aCBkYXRhIGFyZSBub3QgY29uc2lzdGVudDsgdGhleSBhcmUgYWxsIGF0IGlycmVndWxhciBpbnRlcnZhbHMuIFRoZXJlZm9yZSwgdG8gcHV0IHRoZSB0ZW1wZXJhdHVyZSBkYXRhIGludG8gYSBtYXRyaXgsIHdlIGFyZSBnb2luZyB0byBuZWVkIHRvIGJpbiB0aGUgZGF0YSBpbnRvIHJlZ3VsYXIgZGVwdGggaW50ZXJ2YWxzIG9mIDFtLg0KDQpgYGB7cn0NCg0KI3N0YXRpb25MYXQgPC0gYyg0Mys1NC4xMzAvNjAsIDQzKzUxLjgvNjAsIDQzKzQ4LjU2LzYwLCA0Mys0NC44Ny82MCkNCg0KI2NyZWF0aW5nIGFuIGVtcHR5IG1hdHJpeCB3aXRoIDEwMCByb3dzIChpLmUuIGZvciAxMDAgZGVwdGhzKSBhbmQgNCBjb2x1bW5zIChpLmUuIG9uZSBmb3IgZWFjaCBzdGF0aW9uKQ0KVEVNIDwtIG1hdHJpeChOQSxucm93ID0gMTAwLCBuY29sID0gNCkNCg0KI2xvb3BpbmcgdGhyb3VnaCBlYWNoIHN0YXRpb24NCmZvciAoc3QgaW4gMTo0KXsNCiAgI2xvb3BpbmcgdGhyb3VnaCBlYWNoIGRlcHRoIGludGVydmFsIChmcm9tIDFtIHRvIDEwMG0pDQogIGZvciAoaiBpbiAxOjEwMCl7DQogICAgI2V4dHJhY3RpbmcgdGhlIHJlbGV2YW50IHN0YXRpb24gZnJvbSB0aGUgY3J1aXNlRGF0YSBkYXRhIGZyYW1lDQogICAgc3RhdGlvbkRhdGEgPC0gY3J1aXNlRGF0YVtjcnVpc2VEYXRhJFN0YXRpb24gPT0gc3QsXQ0KICAgIA0KICAgICNiaW5uZWQgdGVtcGVyYXR1cmUgdmFsdWUgZm9yIGdpdmVuIGRlcHRoIGludGVydmFsDQogICAgdGVtcCA9IG1lYW4oc3RhdGlvbkRhdGFbY2VpbGluZyhzdGF0aW9uRGF0YSREZXB0aCk9PWosJ1RlbXBlcmF0dXJlJ10pIA0KICAgIA0KICAgICNhc3NpbmdpbmcgdGhlIGJpbm5lZCB0ZW1wZXJhdHVyZSB0byB0aGUgai10aCByb3cgYW5kIHN0LXRoIGNvbHVtbiBvZiB0aGUgVEVNIG1hdHJpeA0KICAgIFRFTVtqLHN0XSA8LSB0ZW1wDQogIH0NCn0NCmBgYA0KDQpOb3cgd2UndmUgY3JlYXRlZCBvdXIgbWF0cml4LCB3ZSBjYW4gcGxvdCB0aGUgdGVtcGVyYXR1cmUgc2VjdGlvbi4NCg0KYGBge3J9DQppbWFnZS5wbG90KHg9MTo0LHk9LTEwMDotMSx0KFRFTVsxMDA6MSw0OjFdKSwNCiAgICAgICAgICAgemxpbT1jKDgsMjApLA0KICAgICAgICAgICBjb2w9dGltLmNvbG9ycygyNCksDQogICAgICAgICAgIHhsYWI9J3N0YXRpb24nLA0KICAgICAgICAgICB5bGFiPSdEZXB0aCAobSknLA0KICAgICAgICAgICBtYWluPSdDcnVpc2UgMjAxNjA5MDgnLA0KICAgICAgICAgICBsZWdlbmQubGFiPSdUZW1wZXJhdHVyZSAoQyknLA0KbGVnZW5kLmxpbmU9Mi41KQ0KDQpgYGANCg0KIyMjIyBFeGFtcGxlOiBIb3cgZG8gd2UgY2hhbmdlIHRoZSBjb2xvciBzY2hlbWU/DQoNCjEuIFdlIGNhbiB1c2Ugb25lIG9mIHRoZSBSIGNvbG9yIHBhbGV0dGVzIGUuZy4gYGhlYXQuY29sb3JzYCwgYHRlcnJhaW4uY29sb3JzYCwgYHRvcG8uY29sb3JzYCBhcyB0aGUgYGNvbGAgYXJndW1lbnQgaW4gcGxhY2Ugb2YgdGhlIGB0aW0uY29sb3JzYCBhcmd1bWVudC4gDQoyLiBXZSBjYW4gdXNlIG9uZSBvZiB0aGUgQ29sb3IgQnJld2VyIHBhbGV0dGVzLiBDb2xvciBCcmV3ZXIgd2FzIGEgcHJvamVjdCB3aGljaCBjcmVhdGVkIGEgbG90IG9mIGRpZmZlcmVudCBjb2xvciBwYWxldHRlcyBmb3IgdGhlbWF0aWMgbWFwcy4gVGhlcmUgYXJlIGRpZmZlcmVudCB0eXBlcyBvZiBjb2xvciBwYWxldHRlcyBkZXBlbmRpbmcgb24geW91ciBuZWVkcyAoZS5nLiBzZXF1ZW50aWFsIGNvbG9yIHNjYWxlLCBkaXZlcmdpbmcgY29sb3Igc2NhbGUsIHF1YW50YXRpdmUgc2NhbGVzKS4gSXQgaGFzIGEgY29vbCB3ZWItaW50ZXJmYWNlIChodHRwOi8vY29sb3JicmV3ZXIyLm9yZy8jKSB3aGVyZSB5b3UgY2FuIHBsYXkgYXJvdW5kIHdpdGggdGhlIHBhbGV0dGVzLiBXaGF0IGlzIGdvb2QgYWJvdXQgQ29sb3IgQnJld2VyIGlzIHRoZSBzZXF1ZW50aWFsIGNvbG9yIHBhbGV0dGVzICh0aGUgdHlwZSB3ZSB1c2VkIGluIG91ciBhYm92ZSBzZWN0aW9uIHBsb3QpIGFyZSBtYWRlIGZyb20gYXQgbW9zdCAzIGNvbG9ycywgYW5kIGFyZSBhbHRlcmVkIGJ5IGNoYW5naW5nIHRoZSBodWUuIFRoaXMgbWFrZXMgdGhlIG1hcHMgY29sb3JibGluZC1mcmllbmRseSBhbmQgcHJldmVudHMgYXJ0aWZpY2lhbCBzaGFycCBlZGdlcyBiZXR3ZWVuIGNvbG9yIGNoYW5nZXMuIFIgaGFzIGEgcGFja2FnZSBmb3IgdGhlIENvbG9yIEJyZXdlciBwYWxldHRlcy4gQ2hlY2sgb3V0IHRoZSBoZWxwIHRvIHNlZSBhIGxpc3Qgb2YgdGhlIHNlcXVlbnRpYWwgcGFsZXR0ZSBuYW1lcyB5b3UgY2FuIHVzZS4NCg0KDQpgYGB7cn0NCmxpYnJhcnkoIlJDb2xvckJyZXdlciIpDQpgYGANCg0KYGBge3J9DQoNCmNvbHBhbCA8LSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOSwnWWxPclJkJykpICAgIyBtYWtlIGNvbG9ycw0KDQppbWFnZS5wbG90KHg9MTo0LHk9LTEwMDotMSx0KFRFTVsxMDA6MSw0OjFdKSwNCiAgICAgICAgICAgemxpbT1jKDgsMjApLA0KICAgICAgICAgICBjb2w9Y29scGFsKDYwKSwNCiAgICAgICAgICAgeGxhYj0nU3RhdGlvbicsDQogICAgICAgICAgIHlsYWI9J0RlcHRoIChtKScsDQogICAgICAgICAgIG1haW49J0NydWlzZSAyMDE2MDkwOCcsDQogICAgICAgICAgIGxlZ2VuZC5sYWI9J1RlbXBlcmF0dXJlIChDKScsDQpsZWdlbmQubGluZT0yLjUpDQpgYGANCg0KDQojIDMuIEFzc2lnbm1lbnQgKGluIGxhYikNCg0KMS4gUGxvdCBhIGNvbnRvdXIgcGxvdCBmb3IgZGlmZmVyZW50IGRpc2NyZXRlIHZhcmlhYmxlcy4gQ2FuIHlvdSBmaWd1cmUgb3V0IGhvdyB0byBjaGFuZ2UgdGhlIGNvbG9yIHNjaGVtZT8NCg0KMi4gUGxvdCBhbiBvY2Vhbm9ncmFwaGljIHNlY3Rpb24gZm9yIGRpZmZlcmVudCB2YXJpYWJsZXMgZnJvbSB0aGUgQ1REIGNhc3RzLiBSZW1lbWJlciB0byBjaGFuZ2UgdGhlIGxpbWl0cyBvZiB0aGUgY29sb3Igc2NhbGUgYnkgYWRqdXN0aW5nIHRoZSBgemxpbWAgYXJndW1lbnQgdG8gYGltYWdlLnBsb3RgLg0KDQo=
>>>>>>> fab0ab19bd3bb006460552ed993a2d3d62575aa9